package com.qianli.cashmama.trade.application.trade;

import com.alibaba.fastjson.JSON;
import com.fqgj.common.api.Page;
import com.fqgj.common.api.Response;
import com.fqgj.common.api.annotations.ParamsValidate;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.TimeUtils;
import com.fqgj.exception.common.ApplicationException;
import com.fqgj.exception.enums.BasicErrorCodeEnum;
import com.google.common.collect.Lists;
import com.qianli.cashmama.trade.client.trade.TradeQueryService;
import com.qianli.cashmama.trade.client.trade.request.*;
import com.qianli.cashmama.trade.client.trade.response.*;
import com.qianli.cashmama.trade.client.vo.RepaymentVO;
import com.qianli.cashmama.trade.client.vo.TradeStatusHistoryVO;
import com.qianli.cashmama.trade.client.vo.TradeVO;
import com.qianli.cashmama.trade.client.vo.UserLevelVO;
import com.qianli.cashmama.trade.common.enums.*;
import com.qianli.cashmama.trade.common.error.TradeErrorCodeEnum;
import com.qianli.cashmama.trade.common.exceptions.TradeException;
import com.qianli.cashmama.trade.dao.*;
import com.qianli.cashmama.trade.domain.event.TradeFlow;
import com.qianli.cashmama.trade.domain.model.TradeBase;
import com.qianli.cashmama.trade.domain.model.TradeDiscount;
import com.qianli.cashmama.trade.domain.services.impl.UserLevelService;
import com.qianli.cashmama.trade.entity.*;
import com.qianli.cashmama.trade.integration.product.ProductIntegrationService;
import com.qianli.cashmama.trade.integration.product.dto.ProductDto;
import com.qianli.cashmama.trade.repo.TradeBaseRepository;
import com.qianli.cashmama.trade.repo.TradeFlowRepository;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created with IntelliJ IDEA.
 * User: sm
 * Date: 2017/8/1
 * Time: 下午9:03
 */
@Service("tradeQueryService")
public class TradeQueryServiceImpl implements TradeQueryService {
    private static final Logger LOGGER = LoggerFactory.getLogger(TradeQueryServiceImpl.class);
    @Autowired
    private TradeFlowRepository tradeFlowRepository;

    @Autowired
    private TradeBaseRepository tradeBaseRepository;

    @Autowired
    private TTradeDao tradeDao;

    @Autowired
    private TTradeExtraDao tTradeExtraDao;

    @Autowired
    private TBankInfoDao bankInfoDao;

    @Autowired
    private TBillDao billDao;

    @Autowired
    private TBizRecordDao bizRecordDao;

    @Autowired
    private ProductIntegrationService productIntegrationService;

    @Autowired
    private UserLevelService userLevelService;

    @Autowired
    private TTradeContractDao tTradeContractDao;

    @Autowired
    private TTradeOpenOrderDao tTradeOpenOrderDao;

    @Autowired
    private TServiceTradeDao tServiceTradeDao;

    @Override
    public Response<TradeInfoResponse> queryByTradeNo(String tradeNo) {
        long start = System.currentTimeMillis();
        LOGGER.info("queryByTradeNo-time,s1:{}", System.currentTimeMillis() - start);
        Response<TradeInfoResponse> response = new Response<>();
        try {
            TradeBase tradeBase = tradeBaseRepository.load(tradeNo);
            if (tradeBase == null) {
                return response.ok().putData(null);
            }

            ProductDto productInfoByCode = productIntegrationService.getProductInfoByCode(tradeBase.getProductCode());
            tradeBase.setBorrowRatio(productInfoByCode.getBorrowRatio());
            LOGGER.info("queryByTradeNo-time,s2:{},content:{}", System.currentTimeMillis() - start, JSON.toJSONString(tradeBase));
            return conventByTradeBase(tradeBase);
        } catch (TradeException e) {
            LOGGER.error("==查询订单失败==,tradeNo:{}", tradeNo, e);
            return response.ok().putData(null);
        } catch (Exception e) {
            LOGGER.error("==查询订单异常==,tradeNo:{}", tradeNo, e);
            return Response.error(TradeErrorCodeEnum.default_error);
        }
    }

    @Override
    public Response<TTradeOpenOrderResponse> queryByOpenTradeNo(String tradeNo) {
        if(StringUtils.isBlank(tradeNo)){
            return Response.error(BasicErrorCodeEnum.PARAM_VALID_ERROR, "tradeNo can not be empty");
        }
        TTradeOpenOrderEntity tTradeOpenOrderEntity = tTradeOpenOrderDao.getByTradeNo(tradeNo);
        TTradeOpenOrderResponse tTradeOpenOrderResponse = null;
        if(tTradeOpenOrderEntity != null){
            tTradeOpenOrderResponse = new TTradeOpenOrderResponse();
            BeanUtils.copyProperties(tTradeOpenOrderEntity, tTradeOpenOrderResponse);
        }
        return Response.ok().putData(tTradeOpenOrderResponse);
    }

    @Override
    public Response<TradeExtraInfoResponse> queryExtraInfoByTradeNo(String tradeNo) {
        if (StringUtils.isEmpty(tradeNo)) {
            return Response.ok();
        }
        TTradeExtraEntity tTradeExtraEntity = tTradeExtraDao.selectByTradeNo(tradeNo);
        if (tTradeExtraEntity == null) {
            return Response.ok();
        }
        TradeExtraInfoResponse tradeExtraInfoResponse = new TradeExtraInfoResponse();
        BeanUtils.copyProperties(tTradeExtraEntity, tradeExtraInfoResponse);
        return Response.ok().putData(tradeExtraInfoResponse);
    }

    /**
     * 根据bizNo查询trade信息
     *
     * @param bizNo
     * @param bizType
     * @return
     */
    @Override
    public Response<TradeInfoResponse> queryByBizNo(String bizNo, BizTypeEnum bizType) {
        Response<TradeInfoResponse> response = new Response<>();
        try {
            TBizRecordEntity bizRecordEntity = bizRecordDao.selectOneByBizNo(bizNo);
            if (bizRecordEntity == null) {
                return response.ok().putData(null);
            }
            TradeBase tradeBase = tradeBaseRepository.load(bizRecordEntity.getInnerNo());
            if (tradeBase == null) {
                return response.ok().putData(null);
            }

            ProductDto productInfoByCode = productIntegrationService.getProductInfoByCode(tradeBase.getProductCode());
            tradeBase.setBorrowRatio(productInfoByCode.getBorrowRatio());

            return conventByTradeBase(tradeBase);
        } catch (TradeException e) {
            LOGGER.error("查询订单失败,bizNo:{}", bizNo, e);
            return response.ok().putData(null);
        } catch (Exception e) {
            LOGGER.error("查询订单异常,bizNo:{}", bizNo, e);
            return Response.error(TradeErrorCodeEnum.default_error);
        }
    }

    @Override
    @ParamsValidate
    public Response<TradeInfoResponse> queryUserLatestTradeByUserCodeAndTradeCategory(QueryUserLatestTradeRequest request) {
        long start = System.currentTimeMillis();
        LOGGER.info("queryUserLatestTrade,request:{}", JSON.toJSONString(request));
        Response<TradeInfoResponse> response = new Response<>();

        try {
            TTradeEntity tradeEntity = tradeDao.selectOneByUserCodeAndProductCategory(request.getProductCategory(), request.getUserCode());
            if (tradeEntity == null) {
                LOGGER.info("queryUserLatestTrade,查无记录:{}", request.getUserCode());
                return response.ok().putData(null);
            }

            LOGGER.info("queryUserLatestTrade-time,s1:{}", System.currentTimeMillis() - start);

            TradeBase tradeBase = tradeBaseRepository.load(tradeEntity.getTradeNo());
            LOGGER.info("queryUserLatestTrade,response:{}", JSON.toJSONString(tradeBase));
            if (tradeBase == null) {
                return response.ok().putData(null);
            }
            LOGGER.info("queryUserLatestTrade-time,s2:{}", System.currentTimeMillis() - start);
            ProductDto productInfoByCode = null;
            try {
                productInfoByCode = productIntegrationService.getProductInfoByCode(tradeBase.getProductCode());
            } catch (Exception e) {
                return response.error(TradeErrorCodeEnum.product_not_exist);
            }
            tradeBase.setBorrowRatio(productInfoByCode.getBorrowRatio());
            LOGGER.info("queryUserLatestTrade-time,s3:{}", System.currentTimeMillis() - start);
            return conventByTradeBase(tradeBase);
        } catch (TradeException e) {
            LOGGER.error("查询用户最后一笔订单失败,query list request:{}", JSON.toJSONString(request), e);
            return response.ok().putData(null);
        } catch (Exception e) {
            LOGGER.error("查询用户最后一笔订单异常,request:{}", JSON.toJSONString(request), e);
            return Response.error(TradeErrorCodeEnum.default_error);
        }
    }

    @Override
    @ParamsValidate
    public Response<TradeInfoRO> queryUserLatestTradeByUserCodeAndTradeCategory(UserLatestTradeQueryRO request) {
        TTradeEntity tradeEntity = tradeDao.selectOneByUserCodeAndProductCategory(request.getProductCategory(), request.getUserCode());
        if (tradeEntity == null) {
            return Response.ok().putData(null);
        }
        TradeInfoRO tradeInfoRO = this.convertEntityToTradeInfoRO(tradeEntity);
        if (request.getNeedCardInfo() != null && request.getNeedCardInfo()) {
            TBankInfoEntity bankInfoEntity = bankInfoDao.selectOneByTradeNo(tradeEntity.getTradeNo());
            if (bankInfoEntity != null) {
                tradeInfoRO.setCardNo(bankInfoEntity.getCardNo());
            }
        }
        return Response.ok().putData(tradeInfoRO);
    }

    private TradeInfoRO convertEntityToTradeInfoRO(TTradeEntity tTradeEntity) {
        TradeInfoRO tradeInfoRO = new TradeInfoRO().setTradeNo(tTradeEntity.getTradeNo())
                .setProductCode(tTradeEntity.getProductCode())
                .setProductCategory(tTradeEntity.getProductCategory())
                .setUserCode(tTradeEntity.getUserCode())
                .setChannelCode(tTradeEntity.getChannelCode())
                .setCustomerCode(tTradeEntity.getCustomerCode())

                .setOrderStatus(TradeStatusEnum.convertByStatus(tTradeEntity.getOrderStatus()))
                .setSignStatus(TradeSignStatusEnum.convertByStatus(tTradeEntity.getSignStatus()))
                .setAuditStatus(TradeAuditStatusEnum.covertByStatus(tTradeEntity.getAuditStatus()))
                .setAuditSubStatus(TradeAuditSubStatusEnum.getEnum(tTradeEntity.getAuditSubStatus()))
                .setPayStatus(TradePayStatusEnum.convertByStatus(tTradeEntity.getPayStatus()))
                .setClientType(TradeClientTypeEnum.getByType(tTradeEntity.getClientType()))

                .setBorrowTotalCapital(tTradeEntity.getBorrowTotalCapital().toString())
                .setReceivedTotalCapital(tTradeEntity.getReceivedTotalCapital().toString())
                .setRepaymentTotalCapital(tTradeEntity.getRepaymentTotalCapital().toString())
                .setPaidTotalCapital(tTradeEntity.getPaidTotalCapital().toString())
                .setTotalServiceFee(tTradeEntity.getTotalServiceFee().toString())

                .setBorrowRatio(tTradeEntity.getBorrowRatio().toString())
                .setTotalPeriod(tTradeEntity.getTotalPeriod())
                .setPaidPeriod(tTradeEntity.getPaidPeriod())
                .setBorrowDuration(tTradeEntity.getBorrowDuration())

                .setOverdueRatio(tTradeEntity.getOverdueRatio().toString())
                .setTotalOverdueServiceFee(tTradeEntity.getTotalOverdueServiceFee().toString())
                .setTotalOverdueFee(tTradeEntity.getTotalOverdueFee().toString())
                .setOrderType(TradeTypeEnum.conventByType(tTradeEntity.getOrderType()))

                .setOverdueServiceFee(tTradeEntity.getOverdueServiceFee().toString())
                .setBorrowDuration(tTradeEntity.getBorrowDuration())
                .setDiscountTotalCapital(tTradeEntity.getDiscountTotalCapital().toString())
                .setPeriodLength(tTradeEntity.getPeriodLength())

                .setReceivedDate(tTradeEntity.getReceivedDate())
                .setCreateDt(tTradeEntity.getGmtCreate())
                .setNewUser(tTradeEntity.getIsNewUser() == 1)
                .setUsageOfLoan(UsageOfLoanEnum.getByCode(tTradeEntity.getUsageOfLoan()))
                .setPayOffDate(tTradeEntity.getPayOffDate())
                .setAuditDate(tTradeEntity.getAuditDate())
                .setExtraData(tTradeEntity.getExtraData())
                .setCapitalCode(StringUtils.isEmpty(tTradeEntity.getCapitalCode()) ? null : tTradeEntity.getCapitalCode())
                .setTradeCloseTypeEnum(this.getTradeCloseTypeByTradeBase(tTradeEntity));
        return tradeInfoRO;
    }

    private TradeCloseTypeEnum getTradeCloseTypeByTradeBase(TTradeEntity tTradeEntity) {
        //处理关闭类型
        TradeCloseTypeEnum tradeCloseTypeEnum = TradeCloseTypeEnum.CLOSE;
        if (tTradeEntity.getOrderStatus() == TradeStatusEnum.MANUAL_CLOSED.getStatus()) {
            if (tTradeEntity.getSignStatus() == TradeSignStatusEnum.SIGN_FAILED.getStatus()) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.SIGN_ERROR;
            } else if (tTradeEntity.getSignStatus() == TradeSignStatusEnum.SIGN_NAME_NOT_MATCH.getStatus()) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.SIGN_ERROR;
            } else if (tTradeEntity.getAuditStatus() == TradeAuditStatusEnum.AUDIT_FAILED.getStatus()) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.AUDIT_REJECT;
            } else if (tTradeEntity.getPayStatus() == TradePayStatusEnum.PAY_FAILED.getStatus()) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.LOAN_REJECT;
            } else if (tTradeEntity.getPayOffDate() != null) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.REPAYMENT_SUCCESS;
            }
        }

        return tradeCloseTypeEnum;
    }

    @Override
    public Response<List<TradeInfoRO>> queryTradeListByUserCodeAndOrderStatus(UserTradeListQueryRO userTradeListQueryRO) {
        List<TTradeEntity> tTradeEntities = tradeDao.selectListByCondition(userTradeListQueryRO.getMerchantCode(), userTradeListQueryRO.getUserCode(), userTradeListQueryRO.getOrderStatus());
        List<TradeInfoRO> list = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(tTradeEntities)) {
            tTradeEntities.forEach(s->{
                TradeInfoRO tradeInfoRO = this.convertEntityToTradeInfoRO(s);
                if (userTradeListQueryRO.getNeedCardInfo()) {
                    TBankInfoEntity bankInfoEntity = bankInfoDao.selectOneByTradeNo(s.getTradeNo());
                    if (bankInfoEntity != null) {
                        tradeInfoRO.setCardNo(bankInfoEntity.getCardNo());
                    }
                }
                list.add(tradeInfoRO);
            });
        }
        return Response.ok().putData(list);
    }

    @Override
    public Response<TradeContractRO> queryTradeContractByTradeNo(String tradeNo) {
        if (StringUtils.isEmpty(tradeNo)) {
            return Response.error(BasicErrorCodeEnum.PARAM_NOT_COMPLETE, "tradeNo can not be empty");
        }
        TTradeContractEntity tTradeContractEntity = tTradeContractDao.selectOneByTradeNo(tradeNo);
        TradeContractRO tradeContractRO = null;
        if (tTradeContractEntity != null) {
            BeanUtils.copyProperties(tTradeContractEntity, tradeContractRO);
        }
        return Response.ok().putData(tradeContractRO);
    }

    @Override
    public Response<UserTradeListResponse> queryUserTradeList(QueryUserTradeRequest request) {
        long start = System.currentTimeMillis();
        LOGGER.info("查询用户的交易列表,request:{}", JSON.toJSONString(request));
        if (StringUtils.isBlank(request.getUserCode())) {
            return Response.error(TradeErrorCodeEnum.user_code_check_failed);
        }
        try {
            Integer closeType;
            if (request.getTradeCloseTypeEnum() == null) {
                closeType = null;
            } else {
                closeType = request.getTradeCloseTypeEnum().getType();
            }
            List<TTradeEntity> tradeEntityList = tradeDao.selectListByUserCodeAndProductCategory(request.getUserCode(), request.getProductCategory(), request.getPage(), request.getClosed(), closeType);
            LOGGER.info("== queryUserTradeList ==,s1:{}", System.currentTimeMillis() - start);
            if (CollectionUtils.isEmpty(tradeEntityList)) {
                return Response.ok().putData(null);
            }
            List<TradeVO> tradeList = new ArrayList<>();
            List<TradeInfoRO> tradeInfoROList = new ArrayList<>();
            for (TTradeEntity entity : tradeEntityList) {
                TBankInfoEntity bankInfoEntity = null;
                if (request.getNeedCardInfo() != null && request.getNeedCardInfo()) {
                    bankInfoEntity = bankInfoDao.selectOneByTradeNo(entity.getTradeNo());
                }
                tradeList.add(new TradeVO()
                        .setTradeNo(entity.getTradeNo())
                        .setApplyDate(entity.getGmtCreate())
                        .setReceivedDate(entity.getReceivedDate())
                        .setBorrowCapital(entity.getBorrowTotalCapital().toString())
                        .setPaidOff(entity.getPayOffDate() != null)
                        .setPeriodUnit(TradeBorrowDurationEnum.convertByType(entity.getBorrowDuration()))
                        .setTotalPeriod(entity.getTotalPeriod())
                        .setTradeStatus(TradeStatusEnum.convertByStatus(entity.getOrderStatus()))
                        .setAuditSubStatus(TradeAuditSubStatusEnum.getEnum(entity.getAuditSubStatus()))
                        .setProductCategory(entity.getProductCategory())
                        .setProductCode(entity.getProductCode())
                        .setBankNo(bankInfoEntity == null ? null : bankInfoEntity.getCardNo())
                        .setBorrowDurationEnum(TradeBorrowDurationEnum.convertByType(entity.getBorrowDuration()))
                        .setPeriodLength(entity.getPeriodLength())
                        .setCloseTypeEnum(getTradeCloseTypeByTradeEntity(entity))
                        .setPaidOffODate(entity.getPayOffDate())
                        .setPaidCapital(entity.getPaidTotalCapital().toString())
                        .setBankName(bankInfoEntity == null ? null : bankInfoEntity.getBankName())
                        .setSignStatusEnum(TradeSignStatusEnum.convertByStatus(entity.getSignStatus()))
                        .setMerchantCode(entity.getMerchantCode())
                );
                TradeInfoRO tradeInfoRO = this.convertEntityToTradeInfoRO(entity);
                tradeInfoRO.setCardNo(bankInfoEntity == null ? null : bankInfoEntity.getCardNo());
                tradeInfoROList.add(tradeInfoRO);
            }

            LOGGER.info("查询用户的交易列表,tradeList size:{}", tradeList.size());
            return Response.ok().putData(new UserTradeListResponse(tradeList, tradeInfoROList, request.getPage()));
        } catch (TradeException e) {
            LOGGER.error("查询用户的交易列表失败,request:{}", request, e);
            return Response.ok().putData(null);
        }
    }

    @Override
    public Response<UserTradeROListResponse> queryUserTradeList(QueryTradeRORequest request) {
        List<TTradeEntity> tTradeEntities = tradeDao.selectListByUserCodeAndProductCategoryAndStatus(request.getUserCode(), request.getProductCategory());
        if (CollectionUtils.isEmpty(tTradeEntities)) {
            return Response.ok().putData(null);
        }
        return Response.ok().putData(new UserTradeROListResponse(this.packageTradeList(tTradeEntities)));
    }

    @Override
    public Response<TradeListResponse> queryUserTradeListByUserCodes(QueryTradesRequest request) {
        List<TTradeEntity> tTradeEntities = tradeDao.selectListByUserCodes(request.getUserCodes());
        if (CollectionUtils.isEmpty(tTradeEntities)) {
            return Response.ok().putData(null);
        }
        return Response.ok().putData(new TradeListResponse(this.packageTradeList(tTradeEntities)));
    }

    @Override
    @ParamsValidate
    public Response<TradeListResponse> queryTradeListByTradeNos(QueryTradeListRequest request) {
        LOGGER.info("== 批量查询订单 ==,request:{}", request);
        Response<TradeListResponse> response = new Response<>();
        try {
            List<TTradeEntity> tradeEntityList = tradeDao.selectListByTradeNosAndPage(request.getTradeNos(), request.getPage());

            if (CollectionUtils.isEmpty(tradeEntityList)) {
                return Response.ok().putData(null);
            }
            return Response.ok().putData(new TradeListResponse(this.packageTradeList(tradeEntityList)));
        } catch (Exception e) {
            LOGGER.error("== 批量查询订单异常 ==,request:{}", request);
            return Response.ok().putData(null);
        }
    }

    @Override
    public Response<TradeListResponse> queryUserTradeListByUserCode(String userCode) {
        if (StringUtils.isBlank(userCode)) {
            return Response.error(BasicErrorCodeEnum.PARAM_NOT_COMPLETE, "userCode can not be empty");
        }
        List<TTradeEntity> tTradeEntities = tradeDao.selectListByUserCode(userCode);

        return Response.ok().putData(new TradeListResponse(this.packageTradeList(tTradeEntities)));
    }

    private List<TradeVO> packageTradeList(List<TTradeEntity> tradeEntityList) {
        List<TradeVO> tradeList = Lists.newArrayList();
        if (CollectionUtils.isEmpty(tradeEntityList)) {
            return tradeList;
        }
        for (TTradeEntity entity : tradeEntityList) {
            TradeVO tradeVO = new TradeVO()
                    .setTradeNo(entity.getTradeNo())
                    .setApplyDate(entity.getGmtCreate())
                    .setReceivedDate(entity.getReceivedDate())
                    .setBorrowCapital(entity.getBorrowTotalCapital().toString())
                    .setPaidOff(entity.getPayOffDate() != null)
                    .setPeriodUnit(TradeBorrowDurationEnum.convertByType(entity.getBorrowDuration()))
                    .setTotalPeriod(entity.getTotalPeriod())
                    .setTradeStatus(TradeStatusEnum.convertByStatus(entity.getOrderStatus()))
                    .setAuditSubStatus(TradeAuditSubStatusEnum.getEnum(entity.getAuditSubStatus()))
                    .setProductCategory(entity.getProductCategory())
                    .setBankNo("")
                    .setBorrowDurationEnum(TradeBorrowDurationEnum.convertByType(entity.getBorrowDuration()))
                    .setPeriodLength(entity.getPeriodLength())
                    .setPaidOffODate(entity.getPayOffDate())
                    .setChannelCode(entity.getChannelCode())
                    .setNewUser(entity.getIsNewUser())
                    .setMerchantCode(entity.getMerchantCode());

            tradeVO.setCloseTypeEnum(getTradeCloseTypeByTradeEntity(entity));
            tradeList.add(tradeVO);
        }
        return tradeList;
    }

    @Override
    public Response<RepaymentListResponse> queryRepaymentList(QueryRepaymentListRequest request) {
        int repaymentStatus = request.getRepaymentStatus();
        List<Integer> tradeStatusList = new ArrayList<>();
        if (repaymentStatus == 0) {
            tradeStatusList.add(TradeStatusEnum.REPAYMENT_WATTING.getStatus());
            tradeStatusList.add(TradeStatusEnum.OVERDUE.getStatus());
            tradeStatusList.add(TradeStatusEnum.NORMAL_REPAYMENT.getStatus());
            tradeStatusList.add(TradeStatusEnum.EARLY_REPAYMENT.getStatus());
            tradeStatusList.add(TradeStatusEnum.OVERDUE_REPAYMENT.getStatus());
            tradeStatusList.add(TradeStatusEnum.MANUAL_CLOSED.getStatus());
            tradeStatusList.add(TradeStatusEnum.PAY_RETRY.getStatus());
        } else if (repaymentStatus == 1) {
            tradeStatusList.add(TradeStatusEnum.REPAYMENT_WATTING.getStatus());
            tradeStatusList.add(TradeStatusEnum.OVERDUE.getStatus());
        } else {
            tradeStatusList.add(TradeStatusEnum.NORMAL_REPAYMENT.getStatus());
            tradeStatusList.add(TradeStatusEnum.EARLY_REPAYMENT.getStatus());
            tradeStatusList.add(TradeStatusEnum.OVERDUE_REPAYMENT.getStatus());
        }

        List<TTradeEntity> tradeEntityList = tradeDao.selectListByUserCodesAndStatusAndTradeNo(request.getUserCodeList(),
                tradeStatusList,
                request.getTradeNo(), request.getProductCategory(), request.getPage());

        if (CollectionUtils.isEmpty(tradeEntityList)) {
            return Response.ok().putData(null);
        }

        List<String> tradeNos = new ArrayList<>();
        for (TTradeEntity tradeEntity : tradeEntityList) {
            if (!tradeNos.contains(tradeEntity.getTradeNo())) {
                tradeNos.add(tradeEntity.getTradeNo());
            }
        }

        List<TBillEntity> billEntityList = billDao.selectListByTradeNos(tradeNos);
        List<TBankInfoEntity> bankInfoEntityList = bankInfoDao.selectListByTradeNos(tradeNos);

        Response<RepaymentListResponse> response = new Response<>();
        return response.ok().putData(conventToRepaymentListResponse(tradeEntityList, billEntityList, bankInfoEntityList, request.getPage()));
    }

    /**
     * 转换得到RepaymentListResponse
     *
     * @param tradeEntityList
     * @param billEntityList
     * @param bankInfoEntityList
     * @param page
     * @return
     */
    public RepaymentListResponse conventToRepaymentListResponse(List<TTradeEntity> tradeEntityList,
                                                                List<TBillEntity> billEntityList,
                                                                List<TBankInfoEntity> bankInfoEntityList,
                                                                Page page) {
        RepaymentListResponse repaymentListResponse = new RepaymentListResponse();
        repaymentListResponse.setPage(page);

        if (CollectionUtils.isEmpty(tradeEntityList)) {
            LOGGER.error("== 查询还款列表为空 ==,,tradeEntityList");
            return repaymentListResponse;
        }

        if (CollectionUtils.isEmpty(billEntityList)) {
            LOGGER.error("== 查询还款列表为空 ==,tradeEntityList");
            return repaymentListResponse;
        }

        Map<String, List<TBillEntity>> tradeNoAndBillMap = new HashMap<>();
        for (TBillEntity billEntity : billEntityList) {
            List<TBillEntity> tempBillEntityList = new ArrayList<>();
            if (tradeNoAndBillMap.containsKey(billEntity.getTradeNo())) {
                tempBillEntityList = tradeNoAndBillMap.get(billEntity.getTradeNo());
            }

            tempBillEntityList.add(billEntity);
            tradeNoAndBillMap.put(billEntity.getTradeNo(), tempBillEntityList);
        }

        Map<String, TBankInfoEntity> tradeNoAndBankMap = new HashMap<>();
        for (TBankInfoEntity bankInfoEntity : bankInfoEntityList) {
            tradeNoAndBankMap.put(bankInfoEntity.getTradeNo(), bankInfoEntity);
        }

        for (TTradeEntity tradeEntity : tradeEntityList) {
            TBankInfoEntity bankInfoEntity = tradeNoAndBankMap.get(tradeEntity.getTradeNo());
            if (bankInfoEntity == null) {
                continue;
            }

            RepaymentVO repaymentVo = new RepaymentVO()
                    .setTradeNo(tradeEntity.getTradeNo())
                    .setMobile(bankInfoEntity.getSignMobile())
                    .setBorrowCapital(tradeEntity.getBorrowTotalCapital().toString())
                    .setTotalPeriod(tradeEntity.getTotalPeriod())
                    .setReceivedCapital(tradeEntity.getReceivedTotalCapital().toString())
                    .setBankCard(bankInfoEntity.getCardNo())
                    .setBankName(bankInfoEntity.getBankName())
                    .setTradeStatus(TradeStatusEnum.convertByStatus(tradeEntity.getOrderStatus()))
                    .setUserCode(tradeEntity.getUserCode());

            List<TBillEntity> billEntities = tradeNoAndBillMap.get(tradeEntity.getTradeNo());
            if (CollectionUtils.isNotEmpty(billEntities)) {
                Map<String, String> payDateMap = new HashMap<>(billEntities.size());
                for (TBillEntity tBillEntity : billEntities) {
                    String acturalRepaymentDate = "";
                    if (tBillEntity.getPayOffDate() != null) {
                        acturalRepaymentDate = TimeUtils.toDateString("yyyy-MM-dd", tBillEntity.getPayOffDate());
                    }
                    payDateMap.put(TimeUtils.toDateString("yyyy-MM-dd", tBillEntity.getRepaymentDate()), acturalRepaymentDate);
                }
                repaymentVo.setPayDateMap(payDateMap);
            }

            repaymentListResponse.getRepaymentList().add(repaymentVo);
        }
        return repaymentListResponse;
    }

    /**
     * 转换tradeBase 到 TradeInfoResponse
     *
     * @param tradeBase
     * @return
     */
    private Response<TradeInfoResponse> conventByTradeBase(TradeBase tradeBase) {
        Response<TradeInfoResponse> response = new Response<>();
        if (tradeBase == null) {
            return response.ok().putData(null);
        }

        TradeInfoResponse tradeInfoResponse = new TradeInfoResponse();
        BeanUtils.copyProperties(tradeBase, tradeInfoResponse);

        tradeInfoResponse.setProductCategory(tradeBase.getProductCategory())
                .setOrderStatus(tradeBase.getTradeOrderStatus())
                .setPayStatus(tradeBase.getTradePayStatus())
                .setAuditStatus(tradeBase.getTradeAuditStatus())
                .setAuditSubStatus(tradeBase.getTradeAuditSubStatus())
                .setReceivedDate(tradeBase.getReceivedDate())

                .setClientType(tradeBase.getClientType())
                .setOrderType(tradeBase.getTradeOrderType())
                .setBorrowTotalCapital(tradeBase.getBorrowTotalCapital().toString())
                .setDiscountTotalCapital(tradeBase.getDiscountTotalCapital().toString())

                .setPaidTotalCapital(tradeBase.getPaidTotalCapital().toString())
                .setOverdueRatio(tradeBase.getOverdueRatio().toString())
                .setBorrowRatio(tradeBase.getBorrowRatio().toString())
                .setReceivedTotalCapital(tradeBase.getReceivedTotalCapital().toString())

                .setTotalServiceFee(tradeBase.getTotalServiceFee().toString())
                .setTotalOverdueServiceFee(tradeBase.getTotalOverdueServiceFee().toString())
                .setTotalOverdueFee(tradeBase.getTotalOverdueFee().toString())
                .setRepaymentTotalCapital(tradeBase.getRepaymentTotalCapital().toString())

                .setApplyDate(tradeBase.getCreatedDate())
                .setProductCode(tradeBase.getProductCode())
                .setBorrowDurationEnum(TradeBorrowDurationEnum.convertByType(tradeBase.getBorrowDuration()))
                .setPeriodLength(tradeBase.getPeriodLength())

                .setNewUser(tradeBase.isNewUser())
                .setPayOffDate(tradeBase.getPayOffDate())

                .setContractUrl(tradeBase.getContractUrl())
                .setSignDate(tradeBase.getSignDate())

                .setTradeSignStatusEnum(tradeBase.getTradeSignStatus())
                .setExtraData(tradeBase.getExtraData())
                .setAuditDate(tradeBase.getAuditDate())
                .setMerchantCode(tradeBase.getMerchantCode());
        //获取订单状态历史
        List<TradeStatusHistoryVO> statusHistoryList = new ArrayList<>();
        List<TradeFlow> tradeFlowList = tradeFlowRepository.queryListByTradeNo(tradeBase.getTradeNo());
        if (!CollectionUtils.isEmpty(tradeFlowList)) {
            for (TradeFlow tradeFlow : tradeFlowList) {
                statusHistoryList.add(new TradeStatusHistoryVO(tradeFlow.getTargetStatus(),
                        tradeFlow.getOperateDate(),
                        tradeFlow.getTargetStatus().getDesc()));
            }
        }

        List<TradeDiscount> tradeDiscountList = tradeBase.getTradeDiscountList();
        if (!CollectionUtils.isEmpty(tradeDiscountList)) {
            tradeInfoResponse.setUserCouponId(tradeDiscountList.get(0).getDiscountCode());
        }


        tradeInfoResponse.setStatusHistoryList(statusHistoryList);

        tradeInfoResponse.setTradeCloseTypeEnum(getTradeCloseTypeByTradeBase(tradeBase));

        return response.ok().putData(tradeInfoResponse);
    }

    @Override
    public Response<TradeListResponse> queryByOrderIds(List<Long> orderIds) {
        Response<TradeListResponse> response = new Response<>();
        if (CollectionUtils.isEmpty(orderIds)) {
            return response.ok().putData(null);
        }
        List<TTradeEntity> tradeEntityList = tradeDao.selectByOrderIds(orderIds);
        List<TradeVO> tradeList = new ArrayList<>();
        for (TTradeEntity entity : tradeEntityList) {
            // 新增返回identityNo
            TBankInfoEntity bankInfoEntity = bankInfoDao.selectOneByTradeNo(entity.getTradeNo());
            bankInfoEntity = (bankInfoEntity == null ? new TBankInfoEntity() : bankInfoEntity);
            TradeVO tradeVO = new TradeVO()
                    .setTradeNo(entity.getTradeNo())
                    .setUserCode(entity.getUserCode())
                    .setApplyDate(entity.getGmtCreate())
                    .setReceivedDate(entity.getReceivedDate())
                    .setBorrowCapital(entity.getBorrowTotalCapital().toString())
                    .setPaidOff(entity.getPayOffDate() != null)
                    .setPeriodUnit(TradeBorrowDurationEnum.convertByType(entity.getBorrowDuration()))
                    .setTotalPeriod(entity.getTotalPeriod())
                    .setTradeStatus(TradeStatusEnum.convertByStatus(entity.getOrderStatus()))
                    .setAuditSubStatus(TradeAuditSubStatusEnum.getEnum(entity.getAuditSubStatus()))
                    .setProductCategory(entity.getProductCategory())
                    .setBankNo(bankInfoEntity.getCardNo())
                    .setBankName(bankInfoEntity.getBankName())
                    .setBorrowDurationEnum(TradeBorrowDurationEnum.convertByType(entity.getBorrowDuration()))
                    .setPeriodLength(entity.getPeriodLength())
                    .setIdentityNo(bankInfoEntity.getIdentityNo());

            tradeVO.setCloseTypeEnum(getTradeCloseTypeByTradeEntity(entity));
            tradeList.add(tradeVO);
        }

        return response.ok().putData(new TradeListResponse(tradeList));
    }

    private TradeCloseTypeEnum getTradeCloseTypeByTradeBase(TradeBase tradeBase) {
        //处理关闭类型
        TradeCloseTypeEnum tradeCloseTypeEnum = TradeCloseTypeEnum.CLOSE;
        if (tradeBase.getTradeOrderStatus().equals(TradeStatusEnum.MANUAL_CLOSED)) {
            if (tradeBase.getTradeSignStatus().equals(TradeSignStatusEnum.SIGN_FAILED)) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.SIGN_ERROR;
            } else if (tradeBase.getTradeSignStatus().equals(TradeSignStatusEnum.SIGN_NAME_NOT_MATCH)) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.SIGN_ERROR;
            } else if (tradeBase.getTradeAuditStatus().equals(TradeAuditStatusEnum.AUDIT_FAILED)) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.AUDIT_REJECT;
            } else if (tradeBase.getTradePayStatus().equals(TradePayStatusEnum.PAY_FAILED)) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.LOAN_REJECT;
            } else if (tradeBase.getPayOffDate() != null) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.REPAYMENT_SUCCESS;
            }
        }

        return tradeCloseTypeEnum;
    }


    private TradeCloseTypeEnum getTradeCloseTypeByTradeEntity(TTradeEntity entity) {

        //处理关闭类型
        TradeCloseTypeEnum tradeCloseTypeEnum = TradeCloseTypeEnum.CLOSE;
        if (entity.getOrderStatus() == TradeStatusEnum.MANUAL_CLOSED.getStatus()) {
            if (entity.getAuditStatus().equals(TradeAuditStatusEnum.AUDIT_FAILED.getStatus())) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.AUDIT_REJECT;
            } else if (entity.getSignStatus().equals(TradeSignStatusEnum.SIGN_NAME_NOT_MATCH.getStatus())) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.SIGN_ERROR;
            } else if (entity.getPayStatus().equals(TradePayStatusEnum.PAY_FAILED.getStatus())) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.LOAN_REJECT;
            } else if (entity.getPayOffDate() != null) {
                tradeCloseTypeEnum = TradeCloseTypeEnum.REPAYMENT_SUCCESS;
            }
        }

        return tradeCloseTypeEnum;
    }


    @Override
    public Response<Integer> countUserSuccessTradeByUserCode(String userCode) {
        Page page = new Page(100);
        List<TTradeEntity> tradeEntityList = tradeDao.selectListByUserCode(userCode, page);

        Integer successCount = 0;
        if (CollectionUtils.isNotEmpty(tradeEntityList)) {
            for (TTradeEntity tradeEntity : tradeEntityList) {
                if (tradeEntity.getPayStatus() == TradePayStatusEnum.PAY_SUCCESS.getStatus()) {
                    successCount++;
                }
            }
        }


        return new Response<>().ok().putData(successCount);
    }


    @Override
    public Response<Integer> countUserActiveTradeByIdentityNo(String identityNo) {
        if (StringUtils.isEmpty(identityNo)) {
            return Response.ok("查询身份证号码为空").putData(null);
        }

        List<TBankInfoEntity> bankInfoEntityList = bankInfoDao.selectListByIdentityNo(identityNo);
        if (CollectionUtils.isEmpty(bankInfoEntityList)) {
            return Response.ok().putData(0);
        }

        List<String> tradeNos = bankInfoEntityList.parallelStream().map(TBankInfoEntity::getTradeNo).collect(Collectors.toList());
        List<TTradeEntity> tradeEntityList = tradeDao.selectListByTradeNos(tradeNos);

        Integer activeCount = 0;
        for (TTradeEntity tradeEntity : tradeEntityList) {
            boolean notClosed = TradeStatusEnum.AUDIT_WATTING.getStatus() == tradeEntity.getOrderStatus() ||
                    TradeStatusEnum.LOAN_WAITTING.getStatus() == tradeEntity.getOrderStatus() ||
                    TradeStatusEnum.REPAYMENT_WATTING.getStatus() == tradeEntity.getOrderStatus() ||
                    TradeStatusEnum.OVERDUE.getStatus() == tradeEntity.getOrderStatus();
            if (notClosed) {
                activeCount++;
            }
        }

        return Response.ok().putData(activeCount);
    }

    @Override
    public Response<Date> getTradeDate() {
        return Response.ok().putData(new Date());
    }


    @Override
    public Response<UserLevelVO> getUserLevel(String userCode, String categoryCode, Integer level, String extraInfo) {
        UserLevelVO userLevelVO = new UserLevelVO()
                .setUserCode(userCode)
                .setCategoryCode(categoryCode)
                .setLevel(level);
        try {
            userLevelVO = userLevelService.getLevel(userCode, categoryCode, level, extraInfo);

        } catch (Exception e) {
            LOGGER.error("== 获取用户等级发生异常 ==,userCode:{},categoryCode:{},level:{},extraInfo:{}", userCode, categoryCode, level, extraInfo, e);

        }
        return Response.ok().putData(userLevelVO);
    }

    @Override
    public Response<Integer> countOrdersByUserCode(String userCode, Boolean closed) {
        return Response.ok().putData(tradeDao.countOrdersByUserCode(userCode, closed));
    }

    @Override
    public Response<Integer> countCurrentDateOrdersByCategoryCode(String categoryCode) {
        return Response.ok().putData(tradeDao.countCurrentDateOrdersByCategoryCode(categoryCode));
    }

    public static void main(String[] args) {
        List<TBillEntity> tBillEntities = new ArrayList<>();
        TBillEntity a = new TBillEntity();
        a.setId(1L);
        tBillEntities.add(a);
        TBillEntity b = new TBillEntity();
        b.setId(2L);
        tBillEntities.add(b);

        Collections.sort(tBillEntities, (TBillEntity b1, TBillEntity b2) -> b2.getId().compareTo(b1.getId()));

        System.err.println(11);

    }

    @Override
    public Response<ServiceTradeInfo> queryServiceTradeInfo(String serviceNo) {
        if(StringUtils.isEmpty(serviceNo)){
            throw new ApplicationException("serviceNo can not be empty");
        }
        TServiceTradeEntity entity = tServiceTradeDao.selectByServiceNo(serviceNo);
        ServiceTradeInfo serviceTradeInfo = null;
        if(entity != null){
            serviceTradeInfo = new ServiceTradeInfo();
            BeanUtils.copyProperties(entity, serviceTradeInfo);
        }
        return Response.ok().putData(serviceTradeInfo);
    }

    @Override
    public Response<Boolean> needPayUserServiceFee(String userCode) {
        List<TServiceTradeEntity> tServiceTradeEntities = tServiceTradeDao.selectByUserCodeAndStatus(userCode, ServiceStatusEnum.SUCCESS.getCode());
        if(CollectionUtils.isNotEmpty(tServiceTradeEntities)){
            return Response.ok().putData(false);
        }else{
            return Response.ok().putData(true);
        }
    }


    @Override
    public Response<Boolean> isWhiteUser(String value, Integer type, String productCategory) {
        LOGGER.info("== isWhiteUser ==,value:{},type:{},productCategory:{}",value,type,productCategory);
        Integer whiteCount = tradeDao.getWhiteCount(productCategory, value, type);
        return Response.ok().putData(whiteCount>0);
    }
}
